package com.ev.apis.controller.custom;

import cn.afterturn.easypoi.entity.vo.TemplateExcelConstants;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.view.PoiBaseView;
import com.ev.apis.model.DsResultResponse;
import com.ev.custom.domain.*;
import com.ev.custom.service.*;
import com.ev.custom.vo.MaterielEntity;
import com.ev.custom.vo.MaterielPageParam;
import com.ev.framework.annotation.EvApiByToken;
import com.ev.framework.annotation.RecoverRemoveData;
import com.ev.framework.config.Constant;
import com.ev.framework.config.ConstantForDevice;
import com.ev.framework.config.ConstantForGYL;
import com.ev.framework.il8n.MessageSourceHandler;
import com.ev.framework.utils.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 物料
 *
 * @author ev-monitor
 * @email 286600136@qq.com
 * @date 2019-07-03 09:40:08
 */
@RestController
@Api(value = "/", tags = "物料管理")
public class MaterielApiController {
    @Autowired
    private MaterielService materielService;
    @Autowired
    private MaterielTypeService materielTypeService;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private FacilityLocationService facilityLocationService;
    @Autowired
    private FacilityService facilityService;
    @Autowired
    private SupplierService supplierService;
    @Autowired
    private MessageSourceHandler messageSourceHandler;
    // 基础税率
    private static final BigDecimal TAX_PERCENT = BigDecimal.valueOf(13L);
    private static final int QUANTITY_ACCURACY = 0;
    private static final int PRICE_ACCURACY = 8;
    private static final long ATTRIBUTE_DICT = 3L;
    private static final long UOM_DICT = 1L;

    @EvApiByToken(value = "/apis/materiel/list", method = RequestMethod.GET, apiTitle = "获取物料列表信息")
    @ApiOperation("获取物料列表信息")
    public R list(@ApiParam(value = "当前第几页", required = true) @RequestParam(value = "pageno", defaultValue = "1") int pageno,
                  @ApiParam(value = "一页多少条", required = true) @RequestParam(value = "pagesize", defaultValue = "20") int pagesize,
                  @ApiParam(value = "物料编码") @RequestParam(value = "serialNo", defaultValue = "", required = false) String serialNo,
                  @ApiParam(value = "物料名称") @RequestParam(value = "name", defaultValue = "", required = false) String name,
                  @ApiParam(value = "成型日报专用") @RequestParam(value = "isDaily", defaultValue = "", required = false) String isDaily,
                  @ApiParam(value = "物料名称&&物料编码") @RequestParam(value = "query", defaultValue = "", required = false) String query,
                  @ApiParam(value = "规格型号") @RequestParam(value = "specification", defaultValue = "", required = false) String specification,
                  @ApiParam(value = "计量单位ID") @RequestParam(value = "unitUom", defaultValue = "", required = false) Integer unitUom,
                  @ApiParam(value = "物料类型ID") @RequestParam(value = "type", defaultValue = "", required = false) Integer type,
                  @ApiParam(value = "物料属性ID") @RequestParam(value = "attribute", defaultValue = "", required = false) Integer attribute,
                  @ApiParam(value = "默认仓库") @RequestParam(value = "defaultFacilityName", defaultValue = "", required = false) String defaultFacilityName,
                  @ApiParam(value = "默认仓位") @RequestParam(value = "defaultLocationName", defaultValue = "", required = false) String defaultLocationName,
                  @ApiParam(value = "状态") @RequestParam(value = "auditSign", defaultValue = "", required = false) Integer auditSign,
                  @ApiParam(value = "启用状态(0禁用，1启用)") @RequestParam(value = "useStatus", defaultValue = "", required = false) Integer useStatus,
                  @ApiParam(value = "是否批次管理") @RequestParam(value = "isLot", defaultValue = "", required = false) Integer isLot,
                  @ApiParam(value = "默认仓库ID") @RequestParam(value = "defaultFacility", defaultValue = "", required = false) Integer defaultFacility,
                  @ApiParam(value = "默认仓位ID") @RequestParam(value = "defaultLocation", defaultValue = "", required = false) Integer defaultLocation,
                  @ApiParam(value = "是否显示已删除数据") @RequestParam(value = "showDeleteData", defaultValue = "0", required = false) Integer showDeleteData,
                  @ApiParam(value = "组织代码") @RequestParam(value = "orgNumber", defaultValue = "") String  orgNumber) {
        Map<String, Object> params = Maps.newHashMap();
        params.put("serialNo", serialNo);
        params.put("name", name);
        params.put("isDaily", isDaily);
        params.put("specification", specification);
        params.put("unitUom", unitUom);
        params.put("type", type);
        params.put("attribute", attribute);
        params.put("query", query);
        params.put("defaultFacilityName", defaultFacilityName);
        params.put("defaultLocationName", defaultLocationName);
        params.put("defaultFacility", defaultFacility);
        params.put("defaultLocation", defaultLocation);
        params.put("isLot", isLot);

        params.put("auditSign", auditSign);
        params.put("useStatus", useStatus);

        params.put("showDeleteData", showDeleteData);

        params.put("offset", (pageno - 1) * pagesize);
        params.put("limit", pagesize);
        params.put("orgNumber", orgNumber);
        Map<String, Object> results = Maps.newHashMapWithExpectedSize(1);
        List<Map<String, Object>> data = this.materielService.listForMap(params);
        int total = materielService.countForMap(params);
        if (data.size() > 0) {
            // 已删除数据启用状态为已删除
            if (showDeleteData==1){
                data.forEach(e->e.put("useStatusName","已删除"));
            }

            results.put("data", new DsResultResponse(pageno, pagesize, total, data));
        }
        return R.ok(results);

    }

    @EvApiByToken(value = "/apis/materiel/typeList", method = RequestMethod.GET, apiTitle = "获取物料类型列表信息")
    @ApiOperation("获取物料类型列表信息")
    public R typeList(@ApiParam(value = "当前第几页", required = true) @RequestParam(value = "pageno", defaultValue = "1") int pageno,
                      @ApiParam(value = "一页多少条", required = true) @RequestParam(value = "pagesize", defaultValue = "20") int pagesize,
                      @ApiParam(value = "物料类型名称") @RequestParam(value = "name", defaultValue = "", required = false) String name) {
        Map<String, Object> params = Maps.newHashMapWithExpectedSize(3);
        params.put("nameSearch", StringUtils.sqlLike(name));
        params.put("offset", (pageno - 1) * pagesize);
        params.put("limit", pagesize);
        Map<String, Object> results = Maps.newHashMapWithExpectedSize(1);
        List<Map<String, Object>> data = this.materielTypeService.listForMap(params);
        int total = this.materielTypeService.count(params);
        if (data.size() > 0) {
            results.put("data", new DsResultResponse(pageno, pagesize, total, data));
        }
        return R.ok(results);

    }

    @EvApiByToken(value = "/apis/materiel/outList", method = RequestMethod.POST, apiTitle = "库存查询")
    @ApiOperation("库存查询")
    public R list(
            @ApiParam(value = "当前第几页", required = true) @RequestParam(value = "pageno", defaultValue = "1") int pageno,
            @ApiParam(value = "一页多少条", required = true) @RequestParam(value = "pagesize", defaultValue = "20") int pagesize,
            @ApiParam(value = "产品类型") @RequestParam(value = "productTypeId", defaultValue = "", required = false) Long productTypeId,
            @ApiParam(value = "产品编号或名称或型号查询") @RequestParam(value = "fuzzySearch", defaultValue = "", required = false) String fuzzySearch,
            @ApiParam(value = "仓库类型") @RequestParam(value = "facilityTypeId", defaultValue = "", required = false) Long facilityTypeId,

            @ApiParam(value = "产品Id") @RequestParam(value = "materielId", defaultValue = "", required = false) Long materielId,
            @ApiParam(value = "批次") @RequestParam(value = "batch", defaultValue = "", required = false) String batch

    ) {
        Map<String, Object> results = Maps.newHashMap();
        Map<String, Object> params = Maps.newHashMap();
        params.put("offset", (pageno - 1) * pagesize);
        params.put("limit", pagesize);
        params.put("productTypeId", productTypeId);
        params.put("fuzzySearch", fuzzySearch);
        params.put("facilityTypeId", facilityTypeId);

        params.put("materielId", materielId);
        params.put("batch", batch);
        params.put("isPc",1);
        // 获取实时库存
        List<Map<String, Object>> data = materielService.stockListForMap(params);
        int total = materielService.stockCountForMap(params);
        if (data.size() > 0) {
            results.put("data", new DsResultResponse(pageno, pagesize, total, data));
        }
        return R.ok(results);
    }

    @EvApiByToken(value = "/apis/materiel/add", method = RequestMethod.POST)
    @ApiOperation("添加物料")
    public R add(MaterielDO materiel) {
        if(StringUtils.isBlank(materiel.getSpecification())){
            materiel.setSpecification(null);
        }
        // 若编号为空 则自动生成
        String serialNo = materiel.getSerialNo();
        Long type = materiel.getType();
        if (type == null) {
            return R.error(messageSourceHandler.getMessage("common.dailyReport.save", null));
        }
        MaterielTypeDO materielTypeDO = materielTypeService.get(type);
        String typeCode = materielTypeDO.getCode();
        if (StringUtils.isBlank(serialNo) || serialNo.startsWith(typeCode)) {
            Map<String, Object> param = Maps.newHashMap();
            param.put("maxNo", typeCode);
            param.put("offset", 0);
            param.put("limit", 1);

            List<MaterielDO> list = materielService.list(param);
            materiel.setSerialNo(DateFormatUtil.getWorkOrderno(typeCode, list.size() > 0 ? list.get(0).getSerialNo() : null, 6));
        }else {
            materiel.setSerialNo(serialNo.trim());
        }


        //  编号不能重复
        List<MaterielDO> materielDOS = materielService.checkSave(materiel);
        if (materielDOS.size() > 0) {
            if (materielDOS.get(0).getDelFlag() == 1) {
                Map<String, Object> result = Maps.newHashMapWithExpectedSize(1);
                result.put("id", materielDOS.get(0).getId());
                return R.error(R.DEL_ERROR, messageSourceHandler.getMessage("common.duplicate.delete.existed", null), result);
            }

            return R.error(messageSourceHandler.getMessage("common.duplicate.serialNoOrName", null));
        }

        if (materielService.save(materiel) > 0) {
            Map<String, Object> result = Maps.newHashMapWithExpectedSize(1);
            result.put("id", materiel.getId());
            return R.ok(result);
        }
        return R.error();
    }

    /**
     * 审核物料
     *
     * @date 2019-12-03
     * @author gumingjie
     */
    @Transactional(rollbackFor = Exception.class)
    @EvApiByToken(value = "/apis/materiel/audit", method = RequestMethod.POST, apiTitle = "审核物料")
    @ApiOperation("审核物料")
    public R audit(
            @ApiParam(value = "物料主键", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
        MaterielDO materielDO = materielService.get(id);
        if (Objects.equals(materielDO.getAuditSign(), Constant.OK_AUDITED)) {
            return R.error(messageSourceHandler.getMessage("common.duplicate.approved", null));
        }
        if (materielService.audit(id) > 0) {
            return R.ok();
        }
        return R.error();
    }

    /**
     * 反审核物料
     *
     * @date 2019-12-03
     * @author gumingjie
     */
    @Transactional(rollbackFor = Exception.class)
    @EvApiByToken(value = "/apis/materiel/reverseAudit", method = RequestMethod.POST, apiTitle = "反审核物料")
    @ApiOperation("反审核物料")
    public R reverseAudit(
            @ApiParam(value = "物料主键", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
        MaterielDO materielDO = materielService.get(id);
        if (Objects.equals(materielDO.getAuditSign(), Constant.WAIT_AUDIT)) {
            return R.error(messageSourceHandler.getMessage("receipt.reverseAudit.nonWaitingAudit", null));
        }
        if (materielService.reverseAudit(id) > 0) {
            return R.ok();
        }
        return R.error();
    }

    @EvApiByToken(value = "/apis/materiel/addType", method = RequestMethod.POST)
    @ApiOperation("添加物料类型")
    public R addType(MaterielTypeDO materielType) {
        String code = materielType.getCode();
        // 编号为空或者不为英文大写字母
        if(StringUtils.isBlank(code) || !code.matches("[A-Z]+")){
            return R.error(messageSourceHandler.getMessage("common.duplicate.code", null));
        }

        //  类型名称和编号不能重复
        if (materielTypeService.checkSave(materielType) == 0) {
            if (materielTypeService.save(materielType) > 0) {
                Map<String, Object> result = Maps.newHashMapWithExpectedSize(1);
                result.put("id", materielType.getId());
                return R.ok(result);
            }
            return R.error();
        }
        return R.error(messageSourceHandler.getMessage("common.duplicate.serialNoOrName", null));
    }

    @EvApiByToken(value = "/apis/materiel/detail", method = RequestMethod.POST)
    @ApiOperation("获取物料详情")
    public R detail(@ApiParam(value = "物料Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
        Map<String, Object> results = this.materielService.getDetail(id);
        if (results == null) {
            return R.error();
        }
        return R.ok(results);
    }

    @EvApiByToken(value = "/apis/materiel/update", method = RequestMethod.POST)
    @ApiOperation("修改物料")
    public R update(MaterielDO materiel) {
        if(StringUtils.isBlank(materiel.getSpecification())){
            materiel.setSpecification(null);
        }
        List<MaterielDO> materielDOS = materielService.checkSave(materiel);
        if (materielDOS.size() > 0) {
            if (materielDOS.get(0).getDelFlag() == 1) {
                Map<String, Object> result = Maps.newHashMapWithExpectedSize(1);
                result.put("id", materielDOS.get(0).getId());
                return R.error(R.DEL_ERROR, messageSourceHandler.getMessage("common.duplicate.delete.existed", null), result);
            }

            return R.error(messageSourceHandler.getMessage("common.duplicate.serialNoOrName", null));
        }
        //  编号不能重复和不能重复名称+规格型号的物料
        materiel.setDelFlag(0);
        if(materiel.getTecRoute()==null){
            materiel.setTecRoute(0L);
        }
        int update = materielService.update(materiel);
        if (update > 0) {
            return R.ok();
        }
        return R.error();
    }

    @EvApiByToken(value = "/apis/materiel/updateType", method = RequestMethod.POST)
    @ApiOperation("修改物料类别")
    public R updateType(MaterielTypeDO materielType) {
        MaterielTypeDO materielTypeDO = materielTypeService.get(materielType.getId());
        if(materielTypeDO.getIsSystem()==1){
            return R.error(messageSourceHandler.getMessage("common.system.disable.operate", null));
        }
        String code = materielType.getCode();
        // 编号为空或者不为英文大写字母
        if(StringUtils.isBlank(code) || !code.matches("[A-Z]+")){
            return R.error(messageSourceHandler.getMessage("common.duplicate.code", null));
        }
        //  类型不能重复
        if (materielTypeService.checkSave(materielType) == 0) {
            int update = materielTypeService.update(materielType);
            if (update > 0) {
                return R.ok();
            }
            return R.error();
        }
        return R.error(messageSourceHandler.getMessage("common.duplicate.serialNoOrName", null));
    }

    @EvApiByToken(value = "/apis/materiel/remove", method = RequestMethod.POST)
    @ApiOperation("删除物料")
    public R remove(@ApiParam(value = "物料Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
        return materielService.logicRemove(id);
    }

    @EvApiByToken(value = "/apis/materiel/batchRemove", method = RequestMethod.POST)
    @ApiOperation("批量删除物料")
    public R batchRemove(@ApiParam(value = "物料Id数组", required = true) @RequestParam(value = "id", defaultValue = "") Long[] ids) {
        return materielService.logicBatchRemove(ids);
    }

    @RecoverRemoveData(tableName = "cus_materiel",columnName = "del_flag",columnValue = "0")
    @Transactional(rollbackFor = Exception.class)
    @EvApiByToken(value = "/apis/materiel/recoverRemoveData", method = RequestMethod.POST)
    @ApiOperation("恢复删除物料")
    public R recoverRemoveData(@ApiParam(value = "物料Id数组", required = true) @RequestParam(value = "id", defaultValue = "") Long[] ids) {
        return R.ok();
    }

    @EvApiByToken(value = "/apis/materiel/removeType", method = RequestMethod.POST)
    @ApiOperation("删除物料类型")
    public R removeType(@ApiParam(value = "物料类型Id", required = true) @RequestParam(value = "id", defaultValue = "") Long id) {
        MaterielTypeDO materielTypeDO = materielTypeService.get(id);
        if(materielTypeDO.getIsSystem()==1){
            return R.error(messageSourceHandler.getMessage("common.system.disable.operate", null));
        }
        Long[] ids = {id};
        // 有关联物料信息则不能删除
        if (materielTypeService.checkDelete(ids) > 0) {
            return R.error(messageSourceHandler.getMessage("common.approvedOrChild.delete.disabled", null));
        }
        if (materielTypeService.remove(id) > 0) {
            return R.ok();
        }
        return R.error();
    }

    @EvApiByToken(value = "/apis/materiel/batchRemoveType", method = RequestMethod.POST)
    @ApiOperation("批量删除物料类型")
    public R batchRemoveType(@ApiParam(value = "物料类型Id数组", required = true) @RequestParam(value = "id", defaultValue = "") Long[] ids) {
        for(Long id : ids){
            MaterielTypeDO materielTypeDO = materielTypeService.get(id);
            if(materielTypeDO.getIsSystem()==1){
                return R.error(messageSourceHandler.getMessage("common.system.disable.operate", null));
            }
        }
        // 有关联物料信息则不能删除
        if (materielTypeService.checkDelete(ids) > 0) {
            return R.error(messageSourceHandler.getMessage("common.approvedOrChild.delete.disabled", null));
        }
        if (materielTypeService.batchRemove(ids) == ids.length) {
            return R.ok();
        }
        return R.error();
    }

    /*导入导出*/
    @ResponseBody
    @EvApiByToken(value = "/apis/exportExcel/materiel", method = RequestMethod.GET, apiTitle = "导出物料")
    @ApiOperation("导出物料")
    public void exportExcel(
            @ApiParam(value = "物料编码") @RequestParam(value = "serialNo", defaultValue = "", required = false) String serialNo,
            @ApiParam(value = "物料名称") @RequestParam(value = "name", defaultValue = "", required = false) String name,
            @ApiParam(value = "物料名称&&物料编码") @RequestParam(value = "query", defaultValue = "", required = false) String query,
            @ApiParam(value = "规格型号") @RequestParam(value = "specification", defaultValue = "", required = false) String specification,
            @ApiParam(value = "计量单位ID") @RequestParam(value = "unitUom", defaultValue = "", required = false) Long unitUom,
            @ApiParam(value = "物料类型ID") @RequestParam(value = "type", defaultValue = "", required = false) Long type,
            @ApiParam(value = "物料属性ID") @RequestParam(value = "attribute", defaultValue = "", required = false) Long attribute,
            @ApiParam(value = "默认仓库") @RequestParam(value = "defaultFacilityName", defaultValue = "", required = false) String defaultFacilityName,
            @ApiParam(value = "默认仓位") @RequestParam(value = "defaultLocationName", defaultValue = "", required = false) String defaultLocationName,
            @ApiParam(value = "状态") @RequestParam(value = "auditSign", defaultValue = "", required = false) Long auditSign,
            @ApiParam(value = "启用状态(0禁用，1启用)") @RequestParam(value = "useStatus", defaultValue = "", required = false) Integer useStatus,
            @ApiParam(value = "默认仓库ID") @RequestParam(value = "defaultFacility", defaultValue = "", required = false) Long defaultFacility,
            @ApiParam(value = "默认仓位ID") @RequestParam(value = "defaultLocation", defaultValue = "", required = false) Long defaultLocation,
            HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) {
        Map<String, Object> param = Maps.newHashMap();
        param.put("serialNo", serialNo);
        param.put("name", name);
        param.put("specification", specification);
        param.put("unitUom", unitUom);
        param.put("type", type);
        param.put("attribute", attribute);
        param.put("query", query);
        param.put("defaultFacilityName", defaultFacilityName);
        param.put("defaultLocationName", defaultLocationName);
        param.put("defaultFacility", defaultFacility);
        param.put("defaultLocation", defaultLocation);

        param.put("auditSign", auditSign);
        param.put("useStatus", useStatus);

        List<Map<String, Object>> data = this.materielService.listForMap(param);
        for (Map<String, Object> datum : data) {
            datum.put("isStockWarning", Integer.parseInt(datum.getOrDefault("isStockWarning", 0).toString()) == 0 ? "否" : "是");
            datum.put("isLot", Integer.parseInt(datum.getOrDefault("isLot", 0).toString()) == 0 ? "否" : "是");
            datum.put("isExpire", Integer.parseInt(datum.getOrDefault("isExpire", 0).toString()) == 0 ? "否" : "是");
        }
        ClassPathResource classPathResource = new ClassPathResource("poi/materiel.xlsx");
        Map<String, Object> map = Maps.newHashMap();
        map.put("list", data);
        TemplateExportParams params = new TemplateExportParams(classPathResource.getPath());
        modelMap.put(TemplateExcelConstants.FILE_NAME, "物料");
        modelMap.put(TemplateExcelConstants.PARAMS, params);
        modelMap.put(TemplateExcelConstants.MAP_DATA, map);

        PoiBaseView.render(modelMap, request, response,
                TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);

    }

    @EvApiByToken(value = "/apis/materiel/batchAudit", method = RequestMethod.POST, apiTitle = "批量审核物料")
    @ApiOperation("批量审核物料")
    @Transactional(rollbackFor = Exception.class)
    public R batchAudit(@ApiParam(value = "供应商id", required = true) @RequestParam(value = "ids", defaultValue = "")Long[] ids ){
        if (ids.length > 0) {
            List<MaterielDO> materielDOList=Lists.newArrayList();
            Long userId = ShiroUtils.getUserId();
            for (Long id : ids) {
                MaterielDO materielDO= materielService.get(id);
                if(Objects.isNull(materielDO)){
                    return R.error(messageSourceHandler.getMessage("common.massge.haveNoThing",null));
                }
                if(!Objects.equals(materielDO.getAuditSign(),Constant.WAIT_AUDIT)){
                    return R.error(messageSourceHandler.getMessage("common.massge.okAudit",null));
                }
                materielDOList.add(materielDO);
            }

            for (MaterielDO materielDO : materielDOList) {
                materielDO.setAuditSign(Constant.OK_AUDITED);
                materielDO.setAuditor(userId);
                materielService.update(materielDO);
            }
            return R.ok();
        }
        return R.error();

    }

    /**
     * 方法描述: [根据条件分页查询物料批次.]</br>
     * 初始作者: ev-monitor<br/>
     * 创建日期: 2020-07-13 12:52:59<br/>
     * 开始版本: 1.0.0<br/>
     * =================================================<br/>
     * 修改记录：<br/>
     * 修改作者 日期 修改内容<br/>
     * ================================================<br/>
     *
     * @param pageParam 分页参数
     * @return R 响应对象
     */
    @EvApiByToken(value = "/apis/materiel/batchList", method = RequestMethod.POST, apiTitle = "根据条件分页查询")
    @ApiOperation(value = "根据条件分页查询", produces = MediaType.APPLICATION_JSON_VALUE)
    public R batchList(@Valid @RequestBody @ApiParam("分页列表参数对象") MaterielPageParam pageParam) {
        return R.ok(this.materielService.batchList(pageParam));
    }

    /*导入*/
    @ResponseBody
    @EvApiByToken(value = "/apis/importExcel/materiel", method = RequestMethod.POST, apiTitle = "物料信息导入")
    @ApiOperation("物料信息导入")
    @Transactional(rollbackFor = Exception.class)
    public R readMateriel(@ApiParam(value = "文件信息", required = true) @RequestParam("file") MultipartFile file,
                          @ApiParam(value = "导入后是否自动审核", required = true) @RequestParam(value = "isAutoAudit",defaultValue = "0") Integer isAutoAudit) {
        if (file.isEmpty()) {
            return R.error(messageSourceHandler.getMessage("file.nonSelect", null));
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(0);
        params.setHeadRows(1);
        String[] importFields = {"物料编码"};
        params.setImportFields(importFields);
        List<MaterielEntity> materielEntityList;
        try {
            materielEntityList = ExcelImportUtil.importExcel(file.getInputStream(), MaterielEntity.class, params);
            materielEntityList = materielEntityList
                    .stream()
                    .filter(e->StringUtils.isNoneEmpty(e.getName()))
                    .collect(Collectors.toList());
        }catch(Exception e) {
            return R.error(messageSourceHandler.getMessage("file.upload.error", null));
        }
        boolean autoAudit = isAutoAudit == 1;
        // 必填项是否必填了
        boolean required = materielEntityList.stream().anyMatch(e->
                 StringUtils.isEmpty(e.getTypeName())
                || StringUtils.isEmpty(e.getAttributeName())
                || StringUtils.isEmpty(e.getUnitUomName())
                || StringUtils.isEmpty(e.getValuationMethodName())
                || Objects.isNull(e.getTaxPercent())
                || StringUtils.isEmpty(e.getName()));
        if (required){
            return R.error(messageSourceHandler.getMessage("data.isRequired.error", null));
        }


        if (materielEntityList.size() > 0) {
            List<String> codeNoneEmptyList = materielEntityList.stream()
                    .filter(materielEntity -> StringUtils.isNoneEmpty(materielEntity.getSerialNo()))
                    .map(MaterielEntity::getSerialNo)
                    .collect(Collectors.toList());
            List<String> nameList = materielEntityList.stream()
                    .map(e -> e.getName() + (e.getSpecification() == null ? "" : "-" + e.getSpecification()))
                    .collect(Collectors.toList());
            List<String> allCode = materielService.getAllCode();
            List<String> allName = materielService.getAllName();
            if (codeNoneEmptyList.size() > 0) {
                allCode.addAll(codeNoneEmptyList);
                List<String> duplicateElements = ListUtils.getDuplicateElements(allCode);
                // 若存在重复的元素提示用户
                if (duplicateElements.size() > 0) {
                    String[] arg = {StringUtils.join(duplicateElements.toArray(), ",")};
                    return R.error(messageSourceHandler.getMessage("basicInfo.code.isPresence", arg));
                }
            }
            if (allName.size() > 0 && nameList.size() > 0) {
                allName.addAll(nameList);
                List<String> duplicateElements = ListUtils.getDuplicateElements(allName);
                // 若存在重复的元素提示用户
                if (duplicateElements.size() > 0) {
                    String[] arg = {StringUtils.join(duplicateElements.toArray(), ",")};
                    return R.error(messageSourceHandler.getMessage("basicInfo.name.isPresence", arg));
                }
            }

            Map<String, Object> param = Maps.newHashMap();
            param.put("maxNo", ConstantForDevice.WL);
            param.put("offset", 0);
            param.put("limit", 1);
            List<MaterielDO> list = materielService.list(param);
            String firstCode = DateFormatUtil.getWorkOrderno(ConstantForDevice.WL, list.size() > 0 ? list.get(0).getSerialNo() : null, 4);

            List<MaterielEntity> codeEmptyList = materielEntityList.stream()
                    .filter(materielEntity -> StringUtils.isEmpty(materielEntity.getSerialNo()) || materielEntity.getSerialNo().startsWith(ConstantForDevice.WL)).collect(Collectors.toList());
            for (MaterielEntity materielEntity : codeEmptyList) {
                materielEntity.setSerialNo(firstCode);
                assert firstCode != null;
                firstCode = ConstantForDevice.WL + StringUtils.autoGenericCode(firstCode.substring(ConstantForDevice.WL.length()), 4);
            }

            Map<String, Object> emptyMap = Maps.newHashMap();
            List<MaterielTypeDO> typeDOs = materielTypeService.list(emptyMap);
            List<DictionaryDO> attributeDOs = dictionaryService.listByType(ConstantForDevice.MATERIAL_TYPE);
            List<DictionaryDO> unitUomDOs = dictionaryService.listByType(ConstantForDevice.UOM_TYPE);
            List<DictionaryDO> valuationMethodDOs = dictionaryService.listByType(ConstantForDevice.VALUATION_METHOD);
            List<FacilityDO> facilityDOs = facilityService.list(emptyMap);
            List<FacilityLocationDO> locationDOs = facilityLocationService.list(emptyMap);
            List<SupplierDO> supplierDOs = supplierService.list(emptyMap);

            List<MaterielDO> materielDOs = Lists.newArrayList();
            MaterielDO materielDO;

            String valuationMethodName;
            String defaultFacilityName;
            String defaultLocationName;
            String supplierName;
            MaterielTypeDO mt;
            DictionaryDO dict;
            for (MaterielEntity materielEntity : materielEntityList) {
                materielDO = new MaterielDO();
                BeanUtils.copyProperties(materielEntity, materielDO);
                if(StringUtils.isBlank(materielDO.getSpecification())){
                    materielDO.setSpecification(null);
                }
                // 物料类别
                String typeName = materielEntity.getTypeName();
                boolean tb = typeDOs.stream().anyMatch(e -> Objects.equals(typeName, e.getName()));
                // 若没有物料类别则新增
                if (!tb){
                    mt = new MaterielTypeDO();
                    mt.setName(typeName);
                    mt.setIsSystem(0);
                    mt.setCode(PinYinUtil.converterToFirstSpell(typeName));
                    materielTypeService.save(mt);
                    typeDOs.add(mt);
                }
                for (MaterielTypeDO materielTypeDO : typeDOs) {
                    if (Objects.equals(materielTypeDO.getName(),typeName)) {
                        materielDO.setType(materielTypeDO.getId());
                        break;
                    }
                }

                // 物料属性
                String attributeName = materielEntity.getAttributeName();
                boolean ab = attributeDOs.stream().anyMatch(e -> Objects.equals(attributeName, e.getName()));
                // 若没有 物料属性则新增
                if (!ab){
                    dict = new DictionaryDO();
                    dict.setName(attributeName);
                    dict.setTypeId(ATTRIBUTE_DICT);
                    dictionaryService.save(dict);
                    attributeDOs.add(dict);
                }
                for (DictionaryDO attributeDO : attributeDOs) {
                    if (Objects.equals(attributeDO.getName(),attributeName)) {
                        materielDO.setAttribute(attributeDO.getId());
                        break;
                    }
                }

                // 计量单位
                String unitUomName = materielEntity.getUnitUomName();
                boolean ub = unitUomDOs.stream().anyMatch(e -> Objects.equals(unitUomName, e.getName()));
                // 若没有计量单位则新增
                if (!ub){
                    dict = new DictionaryDO();
                    dict.setName(unitUomName);
                    dict.setTypeId(UOM_DICT);
                    dictionaryService.save(dict);
                    unitUomDOs.add(dict);
                }
                for (DictionaryDO unitUomDO : unitUomDOs) {
                    if (Objects.equals(unitUomDO.getName(),unitUomName)) {
                        materielDO.setUnitUom(unitUomDO.getId());
                        break;
                    }
                }

                // 计价方法
                valuationMethodName = materielEntity.getValuationMethodName();
                for (DictionaryDO valuationMethodDO : valuationMethodDOs) {
                    if (Objects.equals(valuationMethodDO.getName(),valuationMethodName)) {
                        materielDO.setValuationMethod(valuationMethodDO.getId());
                        break;
                    }
                }
                // 若无计价方法则为加权平均
                if (materielDO.getValuationMethod() == null) {
                    materielDO.setValuationMethod(ConstantForGYL.WEIGHTED_AVERAGE);
                }

                // 默认仓库
                defaultFacilityName = materielEntity.getDefaultFacilityName();
                defaultLocationName = materielEntity.getDefaultLocationName();
                for (FacilityDO facilityDO : facilityDOs) {
                    if (Objects.equals(facilityDO.getName(),defaultFacilityName)) {
                        Long facilityDOId = facilityDO.getId();
                        // 默认库位
                        for (FacilityLocationDO locationDO : locationDOs) {
                            if (Objects.equals(locationDO.getName(),defaultLocationName)) {
                                // 若库位不在该仓库中
                                if (Objects.equals(locationDO.getFacilityId(),facilityDOId)) {
                                    materielDO.setDefaultLocation(locationDO.getId());
                                }
                                break;
                            }
                        }
                        materielDO.setDefaultFacility(facilityDOId);
                        break;
                    }
                }

                // 供应商
                supplierName = materielEntity.getSupplierName();
                for (SupplierDO supplierDO: supplierDOs) {
                    if (Objects.equals(supplierDO.getName(),supplierName)) {
                        materielDO.setSupplier(supplierDO.getId());
                        break;
                    }
                }
                //是否库存预警
                if ("是".equals(materielEntity.getIsStockWarning())) {
                    materielDO.setIsStockWarning(1);
                } else {
                    materielDO.setIsStockWarning(0);
                }

                //是否进行批次管理 （若是分批认定 必定为批次管理）
                if (Objects.equals(materielDO.getValuationMethod(), ConstantForGYL.BATCH_FINDS) || "是".equals(materielEntity.getIsLot())) {
                    materielDO.setIsLot(1);
                } else {
                    materielDO.setIsLot(0);
                }

                //是否进行保质期管理
                if ("是".equals(materielEntity.getIsExpire())) {
                    materielDO.setIsExpire(1);
                } else {
                    materielDO.setIsExpire(0);
                }

                // 设置默认值
                materielDO.setAuditSign(Constant.WAIT_AUDIT);
                // 使用状态(1是0否)
                materielDO.setUseStatus(1);
                materielDO.setTaxPercent(TAX_PERCENT);
                materielDO.setPriceAccuracy(PRICE_ACCURACY);
                materielDO.setQuantityAccuracy(QUANTITY_ACCURACY);
                materielDOs.add(materielDO);
            }
            materielService.batchSave(materielDOs);

            // 是否自动审核
            if (autoAudit){
                Long[] ids = materielDOs.stream().map(MaterielDO::getId).toArray(Long[]::new);
                this.batchAudit(ids);
            }

        }

        return R.ok();
    }
}
